package com.shiro;

import com.domain.Employee;
import com.domain.Role;
import com.service.EmployeeService;
import com.service.PermissionService;
import com.service.RoleService;
import com.util.UserContext;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class CrmRealm extends AuthorizingRealm {
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private RoleService roleService;

    @Autowired
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(credentialsMatcher);
    }

    //提供授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        // 1、获取当前登录的员工对象，获取员工id
        Employee employee = UserContext.getCurrentUser();
        //Employee employee = (Employee) principal.getPrimaryPrincipal();

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        // 2、查询数据库，该员工拥有的角色和权限数据
        //但是超级管理员没有任何角色和权限数据，需要判断
        if (!employee.isAdmin()){
            List<String> expressions = permissionService.selectByEmpId(employee.getId());
            List<String> roleSnList = roleService.selectSnByEmpId(employee.getId());
            // 3、设置当前登录用户拥有的角色和权限数据
            info.addStringPermissions(expressions);
            info.addRoles(roleSnList);  //放入角色的编码
        }else {
            //如果是管理员，给予所有权限
            info.addStringPermission("*:*");
            info.addRole("admin");  //给出自定义角色
        }

        return info;
    }

    //提供认证信息，返回的 Info 相当于用户的信息，被拿去验证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //如果当前方法返回null，shiro会自动抛出 UnknownAccountException
        //如果返回不为null，shiro会自动从返回的对象中获取到真实的密码，再与token（登录页面的令牌）去对比

        // 1、获取令牌中的用户名（前端传来的）
        String username = (String) token.getPrincipal();
        /*UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();*/

        // 2、查询数据库中是否存在
        Employee employee = employeeService.selectByName(username);

        // 3、若不存在，返回null
        // 4、若存在，返回 SimpleAuthenticationInfo
        if(employee != null){
            //判断该账户是否被禁用
            if (!employee.isStatus()){
                throw new DisabledAccountException("账户被禁用");
            }
            //身份信息可以在任意地方获取到，用来跟 subject 绑定在一起的
            //在项目中就直接传入员工对象，跟subject绑定在一起，方便我们后续在任意地方获取当前登录的员工对象
            return new SimpleAuthenticationInfo(employee,  //身份信息，会跟subject绑定在一起
                    //这里传入的是数据库中的真实密码，shiro会自动判断token中的密码是否一致
                    employee.getPassword(),
                    ByteSource.Util.bytes(username), //指定加密时的盐
                    this.getName()//当前Realm数据源的名称,暂时无用,一般是有多个数据源时做标志，表示数据从哪个数据源查出的
            );}
        return null;
    }
}
